/*
	Copyright (c) 2012 by karmaleaving@qq.com. All rights RESERVED.
*/
/*
	This file defines all functors that are in standard lib.
	The extra is those operator-functors which nemed with the end "2"
		such as "equal_to2".
*/
#ifndef __STD_FUNCTION_H_VERSION_SSTD__
#define __STD_FUNCTION_H_VERSION_SSTD__

#include "utility.hpp"

#define _SSTD_USE_BASE_FUNCTION_
#define _SSTD_USE_OPERATOR_FUNCTION_
#define _SSTD_USE_NEGATE_
#define _SSTD_USE_BINDER_
#define _SSTD_USE_POINTER_TO_FUNCTION_
#define _SSTD_USE_MEM_FUN_
#define _SSTD_USE_MEM_FUN_REF_

SSTL_BEGIN

#ifdef _SSTD_USE_BASE_FUNCTION_
template<class ArgType1, class Result>
struct unary_function
{
	typedef ArgType1 argument_type;
	typedef Result result_type;
};
template<typename ArgType1, typename ArgType2, typename Result>
struct binary_function
{
	typedef ArgType1 first_argument_type;
	typedef ArgType2 second_argument_type;
	typedef Result result_type;
};
#endif // _SSTD_USE_BASE_FUNCTION_

#ifdef _SSTD_USE_OPERATOR_FUNCTION_
#define BINARY_OPERATOR_FUNCTION(Return, Operator, Name) \
	template<typename Type> \
struct Name : public binary_function<Type, Type, Return> \
{\
	Return operator () (Type const &value1, Type const &value2) const \
{\
	return value1 Operator value2; \
}\
}
#define UNARY_OPERATOR_FUNCTION(Return, Operator, Name) \
	template<typename Type> \
struct Name : public unary_function<Type, Return> \
{\
	Return operator () (Type const &value) const \
{\
	return Operator value;\
}\
}
#define BINARY_OPERATOR_FUNCTION2(Return, Operator, Name) \
	template<typename TypeL, typename TypeR> \
struct Name : public binary_function<TypeL, TypeR, Return> \
{\
	Return operator () (TypeL const &value1, TypeR const &value2) const \
{\
	return value1 Operator value2; \
}\
}

BINARY_OPERATOR_FUNCTION(Type, + , plus);
BINARY_OPERATOR_FUNCTION(Type, - , minus);
BINARY_OPERATOR_FUNCTION(Type, * , multiplies);
BINARY_OPERATOR_FUNCTION(Type, / , divides);
BINARY_OPERATOR_FUNCTION(Type, % , modulus);
BINARY_OPERATOR_FUNCTION(bool, ==, equal_to);
BINARY_OPERATOR_FUNCTION(bool, !=, not_equal_to);
BINARY_OPERATOR_FUNCTION(bool, < , less);
BINARY_OPERATOR_FUNCTION(bool, > , greater);
BINARY_OPERATOR_FUNCTION(bool, <=, less_equal);
BINARY_OPERATOR_FUNCTION(bool, >=, greater_equal);
BINARY_OPERATOR_FUNCTION(bool, &&, logical_and);
BINARY_OPERATOR_FUNCTION(bool, ||, logical_or);
UNARY_OPERATOR_FUNCTION(bool, !, logical_not);
UNARY_OPERATOR_FUNCTION(Type, -, negate);

BINARY_OPERATOR_FUNCTION2(bool, ==, equal_to2);
BINARY_OPERATOR_FUNCTION2(bool, !=, not_equal_to2);
BINARY_OPERATOR_FUNCTION2(bool, < , less2);
BINARY_OPERATOR_FUNCTION2(bool, > , greater2);
BINARY_OPERATOR_FUNCTION2(bool, <=, less_equal2);
BINARY_OPERATOR_FUNCTION2(bool, >=, greater_equal2);

#undef BINARY_OPERATOR_FUNCTION
#endif // _SSTD_USE_OPERATOR_FUNCTION_

#ifdef _SSTD_USE_NEGATE_
// CLASS unary_negate {
template<typename Func1>
class unary_negate 
	: public unary_function<typename Func1::argument_type, bool>
{
protected:
	Func1 _func;
public:
	explicit unary_negate(Func1 const &fun)
		: _func(fun)
	{
	}
	bool operator() (const typename Func1::argument_type& value) const
	{
		return !(_func(value));
	}
};
// CLASS unary_negate }
// CLASS binary_negate {
template<typename Func2>
class binary_negate 
	: public binary_function<typename Func2::first_argument_type,
	typename Func2::second_argument_type, bool>
{
protected:
	Func2 _func;
public:
	explicit binary_negate(Func2 const &fun)
		: _func(fun)
	{
	}
	bool operator() (const typename Func2::first_argument_type& value1,
		const typename Func2::second_argument_type& value2) const
	{
		return !(_func(value1, value2));
	}
};
// CLASS binary_negate }
// FUNCTION not1 {
template<typename Func1>
unary_negate<Func1> not1(Func1 const &fun)
{
	return unary_negate<Func1>(fun);
}
// FUNCTION not1 }
// FUNCTION not2 {
template<typename Func2>
binary_negate<Func2> not2(Func2 const &fun)
{
	return binary_negate<Func2>(fun);
}
// FUNCTION not2 }
#endif // _SSTD_USE_NEGATE_

#ifdef _SSTD_USE_BINDER_
// CLASS binder1st {
template<typename Func2>
class binder1st 
	: public unary_function<typename Func2::second_argument_type,
	typename Func2::result_type>
{
protected:
	Func2 _func;
	typename Func2::first_argument_type _value;
public:
	binder1st(Func2 const &fun, typename Func2::first_argument_type	const &value)
		: _func(fun), _value(value)
	{
	}
	typename Func2::result_type operator() (typename Func2::argument_type const &value) const
	{
		return _func(_value, value);
	}
};
// CLASS binder1st }
// CLASS binder2nd {
template<typename Func2>
class binder2nd 
	: public unary_function<typename Func2::first_argument_type,
	typename Func2::result_type>
{
protected:
	Func2 _func;
	typename Func2::second_argument_type _value;
public:
	binder2nd(Func2 const &fun, typename Func2::second_argument_type	const &value)
		: _func(fun), _value(value)
	{
	}
	typename Func2::result_type operator() (typename Func2::argument_type const &value) const
	{
		return _func(value, _value);
	}
};
// CLASS binder2nd }
// FUNCTION bind1st {
template<typename Func2>
binder1st<Func2> bind1st(Func2 const &fun, 
						 typename Func2::first_argument_type const &value)
{
	return binder1st<Func2>(fun, value);
}
// FUNCTION bind1st }
// FUNCTION bind2st {
template<typename Func2>
binder2nd<Func2> bind2nd(Func2 const &fun, 
						 typename Func2::second_argument_type const &value)
{
	return binder2nd<Func2>(fun, value);
}
// FUNCTION bind2st }
#endif // _SSTD_USE_BINDER_

#ifdef _SSTD_USE_POINTER_TO_FUNCTION_
// CLASS  pointer_to_unary_function {
template<typename Argument, typename Result, typename Func1 = Result (*)(Argument)>
class pointer_to_unary_function
	: public unary_function<Argument, Result>
{
protected:
	Func1 _func;
public:
	explicit pointer_to_unary_function(Func1 const &fun)
		: _func(fun)
	{
	}
	Result operator() (Argument arg) const
	{
		return _func(arg);
	}
};
// CLASS pointer_to_unary_function }
// FUNCTION ptr_fun {
template<typename Argument, typename Result>
inline pointer_to_unary_function<Argument, Result> ptr_fun(Result (* fun)(Argument))
{
	return pointer_to_unary_function<Argument, Result>(fun);
}
// FUNCTION ptr_fun }
// CLASS pointer_to_binary_function {
template<typename Argument1, typename Argument2, typename Result,
typename Func2 = Result (*)(Argument1, Argument2)>
class pointer_to_binary_function
	: public binary_function<Argument1, Argument2, Result>
{
protected:
	Func2 _func;
public:
	explicit pointer_to_binary_function(Func2 const &fun)
		: _func(fun)
	{
	}
	Result operator() (Argument1 arg1, Argument2 arg2) const
	{
		return _func(arg1, arg2);
	}
};
// CLASS pointer_to_binary_function }
// FUNCTION ptr_fun {
template<typename Argument1, typename Argument2, typename Result>
inline pointer_to_binary_function<Argument1, Argument2, Result> 
ptr_fun(Result (* fun)(Argument1, Argument2))
{
	return pointer_to_binary_function<Argument1, Argument2, Result>(fun);
}
// FUNCTION ptr_fun }
#endif // _SSTD_USE_POINTER_TO_FUNCTION_
#ifdef _SSTD_USE_MEM_FUN_
// CLASS mem_fun_t {
template<typename Result, typename Type>
class mem_fun_t : public unary_function<Type*, Result>
{
protected:
	Result (Type::*_mem_func)();
public:
	explicit mem_fun_t(Result (Type::*fun)())
		: _mem_func(fun)
	{
	}
	Result operator () (Type *ex) const
	{
		return (ex->*_mem_func)();
	}
};
// CLASS mem_fun_t }
// CLASS mem_fun1_t {
template<typename Result, typename Type, typename Argument>
class mem_fun1_t : public binary_function<Type *, Argument, Result>
{
protected:
	Result (Type::*_mem_func)(Argument);
public:
	explicit mem_fun1_t(Result (Type::*fun)(Argument))
		: _mem_func(fun)
	{
	}
	Result operator() (Type * ex, Argument arg) const
	{
		return (ex->*_mem_func)(arg);
	}
};
// CLASS mem_fun1_t }
// CLASS const_mem_fun_t {
template<typename Result, typename Type>
class const_mem_fun_t : public unary_function<Type *, Result>
{
protected:
	Result (Type::*_mem_func)() const;
public:
	explicit const_mem_fun_t(Result (Type::*fun)() const)
		: _mem_func(fun)
	{
	}
	Result operator() (Type const* ex) const
	{
		return (ex->*_mem_func)();
	}
};
// CLASS const_mem_fun_t }
// CLASS const_mem_fun1_t {
template<typename Result, typename Type, typename Argument>
class const_mem_fun1_t : public binary_function<Type *, Argument, Result>
{
protected:
	Result (Type::*_mem_func)(Argument) const;
public:
	explicit const_mem_fun1_t(Result (Type::*fun)(Argument) const)
		: _mem_func(fun)
	{
	}
	Result operator() (Type const* ex, Argument arg) const
	{
		return (ex->*_mem_func)(arg);
	}
};
// CLASS const_mem_fun1_t }
// FUNCTION mem_fun {
template<typename Result, typename Type>
mem_fun_t<Result, Type> mem_fun(Result (Type::*fun)())
{
	return mem_fun_t<Result, Type>(fun);
}
template<typename Result, typename Type, typename Argument>
mem_fun1_t<Result, Type, Argument> mem_fun(Result (Type::*fun)(Argument))
{
	return mem_fun1_t<Result, Type, Argument>(fun);
}
template<typename Result, typename Type>
const_mem_fun_t<Result, Type> mem_fun(Result (Type::*fun)() const)
{
	return const_mem_fun_t<Result, Type>(fun);
}
template<typename Result, typename Type, typename Argument>
const_mem_fun1_t<Result, Type, Argument> mem_fun(Result (Type::*fun)(Argument) const)
{
	return const_mem_fun1_t<Result, Type, Argument>(fun);
}
// FUNCTION mem_fun }
#endif // _SSTD_USE_MEM_FUN_

#ifdef _SSTD_USE_MEM_FUN_REF_
// CLASS mem_fun_ref_t {
template<typename Result, typename Type>
class mem_fun_ref_t : public unary_function<Type, Result>
{
protected:
	Result (Type::*_mem_func)();
public:
	explicit mem_fun_ref_t(Result (Type::*fun)())
		: _mem_func(fun)
	{
	}
	Result operator () (Type &ex) const
	{
		return (ex.*_mem_func)();
	}
};
// CLASS mem_fun_ref_t }
// CLASS mem_fun1_ref_t {
template<typename Result, typename Type, typename Argument>
class mem_fun1_ref_t : public binary_function<Type, Argument, Result>
{
protected:
	Result (Type::*_mem_func)(Argument);
public:
	explicit mem_fun1_ref_t(Result (Type::*fun)(Argument))
		: _mem_func(fun)
	{
	}
	Result operator() (Type &ex, Argument arg) const
	{
		return (ex.*_mem_func)(arg);
	}
};
// CLASS mem_fun1_ref_t }
// CLASS const_mem_fun_ref_t {
template<typename Result, typename Type>
class const_mem_fun_ref_t : public unary_function<Type, Result>
{
protected:
	Result (Type::*_mem_func)() const;
public:
	explicit const_mem_fun_ref_t(Result (Type::*fun)() const)
		: _mem_func(fun)
	{
	}
	Result operator() (Type const &ex) const
	{
		return (ex.*_mem_func)();
	}
};
// CLASS const_mem_fun_ref_t }
// CLASS const_mem_fun1_ref_t {
template<typename Result, typename Type, typename Argument>
class const_mem_fun1_ref_t : public binary_function<Type, Argument, Result>
{
protected:
	Result (Type::*_mem_func)(Argument) const;
public:
	explicit const_mem_fun1_ref_t(Result (Type::*fun)(Argument) const)
		: _mem_func(fun)
	{
	}
	Result operator() (Type const &ex, Argument arg) const
	{
		return (ex.*_mem_func)(arg);
	}
};
// CLASS const_mem_fun1_ref_t }
// FUNCTION mem_fun {
template<typename Result, typename Type>
mem_fun_ref_t<Result, Type> mem_fun_ref(Result (Type::*fun)())
{
	return mem_fun_ref_t<Result, Type>(fun);
}
template<typename Result, typename Type, typename Argument>
mem_fun1_ref_t<Result, Type, Argument> mem_fun_ref(Result (Type::*fun)(Argument))
{
	return mem_fun1_ref_t<Result, Type, Argument>(fun);
}
template<typename Result, typename Type>
const_mem_fun_ref_t<Result, Type> mem_fun_ref(Result (Type::*fun)() const)
{
	return const_mem_fun_ref_t<Result, Type>(fun);
}
template<typename Result, typename Type, typename Argument>
const_mem_fun1_ref_t<Result, Type, Argument> mem_fun_ref(Result (Type::*fun)(Argument) const)
{
	return const_mem_fun1_ref_t<Result, Type, Argument>(fun);
}
// FUNCTION mem_fun_ref }
#endif // _SSTD_USE_MEM_FUN_REF_
SSTL_END

#endif // __STD_FUNCTION_H_VERSION_SSTD__
